package mviewer.types;

import java.util.Collection;
import java.util.LinkedList;
import java.util.Set;

public class Model3dComposite extends Model3d implements IModel3dComposite {

	private Collection<IModel3d> children = new LinkedList<IModel3d>();

	public Model3dComposite() {
		super();
	}

	public Model3dComposite(String name) {
		super(name);
	}

	public Model3dComposite(String name, int vertexCount, int polygonCount) {
		super(name, vertexCount, polygonCount);
	}

	@Override
	public Collection<IModel3d> getChildren() {
		return children;
	}

	@Override
	public void listContainedMaterials(Set<Material> materials) {
		materials.add(getMaterial());
		for (IModel3d model : children)
			model.listContainedMaterials(materials);
	}

	@Override
	public void listContainedModels(Collection<IModel3d> models) {
		models.add(this);

		for (IModel3d model : children)
			model.listContainedModels(models);
	}

	@Override
	public void draw(IDrawerContext drawerContext) {
		throwExceptionIfIllegalState();
		IDrawer drawer = getDrawer(drawerContext);

		drawer.pushTransformation(transformation);
		drawer.draw(new SegregatedDataIterator(getName(), polygons.iterator()), getMaterial());

		for (IModel3d model : children)
			model.draw(drawerContext);

		drawer.popTransformation();
	}

	@Override
	public IModel3d clone() {
		Model3dComposite res = new Model3dComposite(getName() + IModel3d.COPY_SUFFIX, vertices.size(), polygons.size());
		for (IVertex v : vertices)
			res.appendVertex(v.getX(), v.getY(), v.getZ());
		for (TextureCoordinate tc : textureCoordinates)
			res.appendTextureCoordinate(tc.getU(), tc.getV());
		for (Polygon3d p : polygons) {
			TexturedPolygon3d tp = (TexturedPolygon3d)p.getTexturedPolygon();
			res.setMaterial(p.getMaterial());
			if (tp == null)
				res.appendPolygon(p.getVertexIndices());
			else
				res.appendPolygon(tp.getVertexIndices(), tp.getTextureCoordinateIndices());
		}
		res.setMaterial(getMaterial());
		res.transformation = transformation;
		// copy already rendered normals
		for (int i = 0; i < normals.size(); i++) {
			res.normals.get(i).setX(normals.get(i).getX());
			res.normals.get(i).setY(normals.get(i).getY());
			res.normals.get(i).setZ(normals.get(i).getZ());
		}
		res.modified = false;

		for (IModel3d model : children)
			res.children.add(model.clone());

		return res;
	}

	@Override
	public float retrieveLowestX() {
		float tmp, res = super.retrieveLowestX();

		for (IModel3d model : children) {
			tmp = model.retrieveLowestX();
			if (tmp < res)
				res = tmp;
		}

		return res;
	}

	@Override
	public float retrieveHighestX() {
		float tmp, res = super.retrieveHighestX();

		for (IModel3d model : children) {
			tmp = model.retrieveHighestX();
			if (tmp > res)
				res = tmp;
		}

		return res;
	}

	@Override
	public float retrieveLowestY() {
		float tmp, res = super.retrieveLowestY();

		for (IModel3d model : children) {
			tmp = model.retrieveLowestY();
			if (tmp < res)
				res = tmp;
		}

		return res;
	}

	@Override
	public float retrieveHighestY() {
		float tmp, res = super.retrieveHighestY();

		for (IModel3d model : children) {
			tmp = model.retrieveHighestY();
			if (tmp > res)
				res = tmp;
		}

		return res;
	}

	@Override
	public float retrieveLowestZ() {
		float tmp, res = super.retrieveLowestZ();

		for (IModel3d model : children) {
			tmp = model.retrieveLowestZ();
			if (tmp < res)
				res = tmp;
		}

		return res;
	}

	@Override
	public float retrieveHighestZ() {
		float tmp, res = super.retrieveHighestZ();

		for (IModel3d model : children) {
			tmp = model.retrieveHighestZ();
			if (tmp > res)
				res = tmp;
		}

		return res;
	}
}
